;**********************************************************
;
;		USRDFLT2.CCP by R. L. Plouffe
;		       (703) 527-3215
;			June 4, 1981
;
;		For CP/M 2.x systems only.
;
;	Changed the code that restricts access to
;	USER areas in order to take advantage of
;	routines already in the CCP. Reduces the
;	code that must be placed in your customiz-
;	ed bios considerably...........RLP 6/4/81
;
;  	Originally written 5/26/81. This has been
;	re-written to clean it up and to add labels
;	and comments so it can be easily read.
;	...............................RLP 5/31/81
;
;These routines are based on ideas and code found on the
;CALAMITY CLIFFS machine.  Authors are apparently Ron Fowler
;and Keith Peterson. What is done here is to integrate these
;ideas and to add two important new features.  First a new
;kind of CCP command is added that is a pseudo CCP transient.
;These commands reside on disk as a transient, but may be called
;from any user area and any logged drive as long as they reside
;on drive A and in a pre-designated USER area. Second, the newly
;defined pseudo CCP/transients as well as existing (or additional)
;CCP commands may be defined as either public or private with
;private commands being accessible only after becoming password
;privileged. It should be apparent that among other things, these
;integrated routines avoid the necessity of placing copies of
;transient routines that are included in the pseudo definition
;in multiple USER areas. Certainly a must for PIP at least.

;Add this code to your customized user or BIOS file and the
;CCP patches will be automatically overlayed when you put it
;in with DDT provided that your file contains an equate for
;the CCP beginning address for your system size. NOTE that the
;command address table and the command strings have been taken
;out of the CCP.  However, the code space that they occupied has
;been well stuffed with other patch code. An 18 byte spare area
;at the end of the BDOS is also used. Make sure that your version
;has this spare area still available and has not been used by some-
;ones customization.  If it has, then place the code at the label
;BRIDGE into your customized BIOS.

;Donated for the benefit of hobby computing.  This creation
;may not be sold.
;
;
CCP	EQU	YOUR CCP ADDRESS	;BASE OF CCP
;
BDOS	EQU	CCP+800H		;BASE OF BDOS
BIOS	EQU	CCP+1600H		;BASE OF BIOS
DFCB	EQU	5CH		;ADDR OF DEFAULT FILE CNTRL BLK
DRIVE	EQU	04H		;LOC OF CURRENT DRIVE BYTE
CR	EQU	0DH
LF	EQU	0AH
;
LENCMD	EQU	5		;LENGTH OF CCP CMD STRINGS
MAXUSER	EQU	4		;FOR EXAMPLE
BUFSIZE	EQU	CCP+6H		;LOC OF SIZE BYTE FOR CCP BUF
BDOSFNC	EQU	BDOS+6H		;BDOS FUNCTION
GETUSR	EQU	CCP+113H	;GET USER #
SETUSR	EQU	CCP+115H	;SET USER #
TSTUSR	EQU	CCP+692H	;TEST USER #
USRSAV	EQU	CCP+118H
CCPPASS	EQU	CCP+7EH		;LOCATION OF CCP PASSWORD
UPATCH0	EQU	CCP+390H
UPATCH1	EQU	CCP+393H
HUH	EQU	CCP+209H	;CCP HUH RESPONSE
CRLF	EQU	CCP+98H		;CCP CR/LF FUNCTION
RETCCP	EQU	CCP+382H	;RE-ENTRY TO CCP
CMDPTR	EQU	CCP+3B5H	;POINTER TO COMMAND ADDR TBL
STRPTR	EQU	CCP+32FH	;POINTER TO CCP CMD STRINGS
CMDCNT	EQU	CCP+335H	;BYTE VALUE = # OF COMMANDS
CMDLEN	EQU	CCP+33BH	;BYTE VALUE = LENGTH OF EACH
				;COMMAND STRING.
TSTOPN	EQU	CCP+6DCH	;TEST FILE OPEN FUNCTION
CMDDRV	EQU	CCP+7F0H	;BYTE INDICATES DRV IN CMD
CMDERR	EQU	CCP+76BH	;HUH RESPONSE IF DR #
XTNSN	EQU	CCP+7D6H	;STORAGE LOC FOR FILE TYPE,
				;EXT #, AND RECORD COUNT
RELOOK	EQU	CCP+6CDH	;RELOOK W/INDICATED DRIVE
TPASUB	EQU	CCP+75DH	;LOC TO SUSTITUTE BEFORE
				;CALLING THE TPA
CONTINUE EQU	CCP+75FH	;TO CONTINUE AFTER CALL TO TPA
GETRANS	EQU	CCP+6A5H	;GET TRANS OR CCP COMMAND
ERA	EQU	CCP+51FH	;ADDR OF ERA ROUTINE
REN	EQU	CCP+610H	;ADDR OF REN ROUTINE
SAVE	EQU	CCP+5ADH	;ADDR OF SAVE ROUTINE
DIR	EQU	CCP+477H	;ADDR OF DIR ROUTINE
TYPE	EQU	CCP+55DH	;ADDR OF TYPE ROUTINE
USER	EQU	CCP+68EH	;ADDR OF USER ROUTINE
TPA	EQU	100H		;OR YOUR TPA ADDRESS
CCPSPARE EQU	CCP+7F2H	;14 SPARE BYTES AT END OF CCP
BDOSPARE EQU	BDOS+0DEEH	;18 SPARE BYTES AT END OF BDOS
	;Addresses of holes left in CCP that are filled in
	;with patches for transient user defaults
HOLE1	EQU	CCP+310H	;EXACTLY 24 BYTES HERE
HOLE2	EQU	CCP+3C1H	;   "     6   "     "
HOLE3	EQU	CCP+3C7H	;   "     8   "     "
;
;**********************************************************
;	BEGINNING OF CODE THAT IS PATCHED INTO THE CCP
;**********************************************************
;This is the CCP password to obtain privilege to higher USER
;areas and privileged CCP or transient commands.  The password
;itself is ORGed at the very end of the CCP command buffer.
;The buffer is resized to permit this location. The advantage
;to this ORG is that any attempt to find it with DDT will be
;unsuccessful since DDT overlays the CCP, so this is an added
;measure of security. If you lengthen the password, reduce the
;value of the CCPPASS equate for each additional character in the
;password.  Password may be mixed upper and lower case characters.
;
	ORG	CCPPASS
PASSWD:	DB	'URPASSWRD',CR
	ORG	BUFSIZE
	DB	75H		;10 bytes less than original
;
;The CCP-included command 'PASS' routine is at CKCCPAS which
;is located in your customized BIOS.
;**********************************************************
; This patch is used to restrict access to the higher user
; areas while leaving the lower user areas public. The high-
; est available public user area is defined by MAXUSER.
;
	ORG	USRSAV
	DW	SAVUSR		;ADDR TO JMP TO SO THAT
				;CALLING USER NUMBER IS RE-
				;TURNED TO AFTER EXECUTING
				;A TRANSIENT
;The routines are located in your customized BIOS.
;**********************************************************
; This patch causes user number to be reported at the cp/m
; prompt.....i.e. - A2>.  User 0 report is suppressed.
;
	ORG	UPATCH0
	MVI	C,USRFNC	;VALUE FOR USER FNC CALL
	ORG	UPATCH1
	DW	UPATCH		;ADDR OF PATCH TO CALL
;the routine UPATCH is located in the USER area of your
;customized BIOS
;**********************************************************
; This patch causes the CCP of a cp/m 2.x system to look on
; drive A when you are logged into a drive other than A and
; call for a .COM file that does not exist on that drive.
; Giving an explicit drive reference overrides this feature,
; so that you can always force the file to be loaded from a
; specific drive.
;
	ORG	TSTOPN
	DW	APATCH		;REPLACES 'CMDERR'
;
	ORG	CCPSPARE
APATCH:	LXI	H,CMDDRV	;GET DRIVE FROM CURRENT CMD.
	ORA	M		;FETCHES DRIVE
	JNZ	CMDERR		;GIVE ERROR IF CMD HAS DRIVE #
	INR	M		;FORCE TO DRIVE A
	LXI	D,XTNSN		;UNDO WHEN...
	JMP	RELOOK		;REENTERING CCP
;
;**********************************************************
;This patch extends the CCP to include up to N additional
;commands that are user defined. The commands may be either
;CCP-included or transient, and may be either private or
;public depending on password privilege.
;
	ORG	CMDPTR
CMDPTR:	DW	CMDTBL2		;COMMAND TABLE ADDRESS (PUBLIC)
	;
	ORG	STRPTR
STRPTR:	DW	CMDSTR2		;COMMAND STRING ADDRESS (PUBLIC)
	;
	ORG	CMDCNT
CMDCNT:	DB	(GETRAN0-CMDTBL2)/2 ;TO LIMIT PUBLIC ACCESS TO CCP
				   ;COMMANDS. RESET TO ALL WHEN 
				   ;PASSWORD IS ENTERED FOR USER
				   ;AREAS ABOVE MAXUSER.
	ORG	CMDLEN
CMDLEN:	DB	LENCMD		;LENGTH OF CCP COMMAND STRINGS

;The rest of this patch is in the USER area of your customized
;BIOS.
;
;**********************************************************
;This is the routine that cause those utilities which are in
;the CCP command table to be available from all user areas.
;They must be resident in USER 0 or 15 and named the same as in 
;command string....i.e, 'EDIT' for 'WORDSTAR',  'STAT' for 'STAT',
;etc.. The names and addresses can be in either the public or
;private areas. Don't expand this code except to use indicated
;spare bytes because you will wipe out other good code if you
;do.
;
	ORG	HOLE2
TRDFLT0:
	MVI	E,0		;VALUE FOR PUBLIC TRANSIENTS
	PUSH	D		;SAVE IT ON THE STACK
	JMP	DFLT		;TO DEFAULT TO USER VALUE
	ORG	HOLE1
TRDFLT15:
	MVI	E,15		;VALUE FOR PRIVATE TRANSIENTS
	PUSH	D		;SAVE IT ON THE STACK
DFLT:	
	CALL	GETUSR		;GET CALLING USER #
	STA	HOLDUSER	;SAVE IT
	POP	D		;GET DEFAULT USER VALUE IN E
	CALL	SETUSR		;SET THE USER # IN BDOS
	LXI	H,RSTUSR	;PUT ADDR OF RTNE IN HL
	SHLD	TPASUB		;SET TO CALL IT INSTEAD OF TPA
	JMP	GETRANS		;GET THE FILE TO THE TPA
	DB	0,0		;SPARE BYTES
;
	ORG	HOLE3
RSTUSR:	LDA	HOLDUSER	;GET THE SAVED USER #
	MOV	E,A		;PUT IT IN E
	JMP	BRIDGE
HOLDUSER:
	DB	0
	ORG	BDOSPARE	;SPARE BYTES HERE IN BDOS
BRIDGE:	CALL	SETUSR		;SET USER #
	LXI	H,TPA		;PUT ADDR OF TPA IN HL
	SHLD	TPASUB		;SET TO CALL TPA NEXT TIME
	CALL	TPA		;DO IT NOW
	JMP	CONTINUE	;BACK TO CCP IN-LINE CODE
	DB	0,0,0		;SPARES
;
;	END OF CODE THAT IS PATCHED INTO THE CCP (AND BDOS)
;			*****
;
;**********************************************************
;	BEGINNING OF CODE THAT IS PUT IN YOUR BIOS.
;	SEE GENESYS AND GENEUSER FOR A TECHNIQUE TO
;	EXPAND YOUR USER AREA.
;**********************************************************

	ORG	BIOS+WHATEVER

;This is the command string which is divided into private
;and public sections. Do not use more than five letters for
;the name of any command or transient and fill out each string
;to exactly five characters by using spaces below. Each string
;must occur at 5 character intervals.  If you wish to use some
;other string length such as 4 as in the original CCP, just
;change the string lengths below and change the LENCMD equate
;from 5 to 4.  I use 5 below so that MODEM can fit.
;
CMDSTR1:
	DB	'ERA  REN  SAVE STAT PIP  DDT  ASM  LOAD COPY EDIT '
CMDSTR2:
	DB	'SRD  DIR  TYPE USER PASS MODEMBYE  CRCK '
;
;**********************************************************
;This is the command address table which is divided into
;private and public areas. The address of the routine to be
;jumped to must be here for any CCP-included code as well as
;any that you add and put in your customized BIOS. For private
;and public transients, use TRDFLT15 AND TRDFLT0 respectively
;and put private transients in USER 15 on your system disk (A).
;Similarly, put public transients in USER 0 on 'A'. These trans-
;ients will now be available from any drive and from any USER #
;depending on password privilege.  You can expand the table to
;any extent that you have space and the command string above
;must be expanded in synchronism.
;
;Put the private transients in USER 15
CMDTBL1:
	DW	ERA		;ERA....PRIVATE COMMANDS
	DW	REN		;REN
	DW	SAVE		;SAVE
	DW	TRDFLT15	;STAT...THE FOLLOWING UTILITIES
	DW	TRDFLT15	;PIP....WILL BE TREATED AS CCP
	DW	TRDFLT15	;DDT....COMMANDS. THEY MUST BE ON
	DW	TRDFLT15	;ASM....DISK AS TRANSIENTS AT USER 15
	DW	TRDFLT15	;LOAD...AND WILL NOW BE AVAILABLE AT
	DW	TRDFLT15	;COPY...ALL USER #'S
	DW	TRDFLT15	;EDIT (RENAME WORDSTAR TO EDIT),
				;or whatever your favorite editor is.
;Put the public transients below in USER 0
CMDTBL2:
	DW	TRDFLT0		;SRD ....PUBLIC COMMANDS
	DW	DIR		;DIR
	DW	TYPE		;TYPE
	DW	USER0		;USER
	DW	CKCCPAS		;PASS(WORD)
	DW	TRDFLT0		;MODEM for Ward's MODEM program.
				;I use this command for either
				;XMODEM or MODEM7 depending on
				;which one I have on drive A.
	DW	TRDFLT0		;BYE  for Ward's BYE program
	DW	TRDFLT0		;CRCK does a CRC 16 check on file
GETRAN0:			;This must be last entry in table.
	DW	GETRANS		;Get the transient and execute or
				;return to CCP w/HUH message if not
				;on disk.
;
;**********************************************************
;This patch which is called from the CCP provides for a
;report of USER number at the prompt....i.e. A2> for USER 2,
;'A' drive.
;
UPATCH:	LDA	PASSFLG		;GET PASSWORD FLAG
	INR	A		;SEE IF SET
	JNZ	UPATCH2		;SKIP IF NOT
	LXI	H,CMDSTR1	;SET CMDSTRING POINTER TO
				;BEGINNING OF ALL COMMANDS
	SHLD	STRPTR		;STORE IT IN STRING POINTER
	LXI	H,CMDTBL1	;SET CMDTABLE POINTER TO
				;BEGINNING OF ALL CMD ADDRESSES
	SHLD	CMDPTR		;STORE IT IN COMMAND TABLE POINTER
	MVI	A,(GETRAN0-CMDTBL1)/2 ;CALC # OF COMMANDS
	STA	CMDCNT		;STORE VAL IN SCAN ROUTINE IN CCP
UPATCH2:
	CALL	GETUSR		;GET USER NUMBER
	ANI	0FH		;KILL UNWANTED BITS
	JZ	UPA2		;IF USER 0, DON'T REPORT
	CPI	10
	JC	UPA1		;JIF USER NUM = 0 THRU 9
	SUI	10		;USER NUM = 10 THRU 15
	PUSH	PSW
	MVI	E,'1'
	MVI	C,CONSOUT	;VAL FOR CONSOLE OUT FNC
	CALL	BDOSFNC		;PRINT A '1'
	POP	PSW
;
UPA1:	ADI	'0'
	MOV	E,A
	MVI	C,CONSOUT	;VAL FOR CONSOLE OUT FNC
	CALL	BDOSFNC		;PRINT DIGIT
;
UPA2:	MVI	E,'>'
	MVI	C,CONSOUT	;VAL FOR CONSOLE OUT FUNCTION
	JMP	BDOSFNC		;PRINT '>', EXIT
;
;**********************************************************
;These are the routines which provide for limited USER area
;access.  USER0 is jumped to before jumping from the CCP com-
;and parser to the CCP-included USER routine.  SAVUSR is jumped
;to whenever resetting the user code and guarantees that the
;same user area will be returned to as was in effect before
;executing a transient command.
;
USER0:	LDA	PASSFLG		;SEE IF PRIVILEGED
	INR	A		;YES?
	JZ	USER		;TO USER CODE IF SO
	MVI	A,MAXUSER+1	;RESTRICT ACCESS
	STA	TSTUSR		;DO IT HERE
	JMP	USER		;GOTO CCP USER CODE
;
SAVUSR:	MOV	A,E		;SEE IF GET OR SET USER
	CPI	0FFH		;IS IT GET USER?
	JZ	BDOSFNC
	MOV	A,E		;GET USER #
	RLC
	RLC
	RLC
	RLC			;MOVE TO UPPER NIBBLE
	MOV	B,A		;SAVE REQUESTED USER #
	LDA	DRIVE		;GET CURRENT USER/DRIVE
	ANI	0FH		;STRIP OFF OLD USER #
	ORA	B		;GET NEW USER #
	STA 	DRIVE		;SET NEW USER #
	JMP	BDOSFNC		;SET IT AND EXIT
;
PASSFLG:
	DB	0		;STORE FOR PASSWORD FLAG
CKCCPAS:
	LXI	H,PASSWD	;POINT TO PASSWORD	
CKPASS:	LDA	PASSFLG		;GET PASSWORD FLAG
	INR	A		;SEE IF SET
	JZ	RETCCP		;IF SO, RET TO CCP
	CALL	CRLF		;DO A CR/LF
	MVI	D,0		;NO MISSED LETTERS
PWMLP:	PUSH	D
	PUSH	H
PWMLP1:	MVI	C,DIRCONIO	;GET A CHAR
	MVI	E,0FFH		;SET TO CONSOLE IN
	CALL	BDOSFNC		;DO IT
	ORA	A		;SEE IF CHAR ENTERED
	JZ	PWMLP1		 ;LOOP IF NOT
	POP	H	
	POP	D
	CMP	M		;MATCH PASSWORD?
	JZ	PWMAT		;..YES
	MVI	D,1		;..NO, SHOW MISS
	CPI	CR
	JNZ	PWMLP		;..NO, WAIT FOR C/R
	JMP	HUH		;RETURN TO CCP WITH A HUH
;
PWMAT:
	INX	H
	CPI	CR		;SEE IF END OF PASSWORD
	JNZ	PWMLP		;GET ANOTHER CHAR IF NOT
	MOV	A,D		;ERROR INDICATOR TO A
	ORA	A		;ERROR?
	JNZ	HUH		;IF SO, SAY HUH
	MVI	A,0FFH		;VAL FOR PASSWORD FLAG
	STA	PASSFLG		;SET IT
	MVI	A,16		;RESTORE
	STA	TSTUSR		;ALL USER AREAS
	JMP	RETCCP		;AND RETURN TO CCP
;
;
;BDOS FUNCTION CALL EQUATES
;
CONSOUT	EQU	2		;CONSOLE OUTPUT
DIRCONIO EQU	6		;DIRECT CONSOLE INPUT OUTPUT
USRFNC	EQU	32		;USER FUNCTION CODE
;
;	the
	END
;	for now
